const _ = {
  send: null,
  table: null,
  objects: {},
  selected: null,
  players: null,
  me: null,
  newTable(width, height) {
    if (_.table) {
      document.body.removeChild(_.table)
      _.objects = {}
      _.selected = null
      menu.close()
    }
    _.table = document.createElement('div')
    document.body.appendChild(_.table)
    _.table.className = 'table'
    _.table.oncontextmenu = e => e.preventDefault()
    _.table.onmouseup = e => {
      if (e.button == 0) {
        if (_.selected) {
          if (_.selected.list) {
            _.send({
              type: 'moveAll',
              list: _.selected.list,
              deltaX: e.pageX - _.selected.objX - _.selected.element.obj.left,
              deltaY: e.pageY - _.selected.objY - _.selected.element.obj.top
            })
          } else {
            _.send({
              type: 'move',
              objectId: _.selected.element.obj.id,
              toX: e.pageX - _.selected.objX,
              toY: e.pageY - _.selected.objY
            })
          }
          _.cancelMySelect()
        } else {
          if (menu.isOpen()) {
            menu.close()
            return
          }
        }
      } else if (e.button == 2) {
        if (_.selected) {
          if (_.selected.list) {
            _.send({
              type: 'cancelAll',
              list: _.selected.list
            })
          } else {
            _.send({
              type: 'cancel',
              objectId: _.selected.element.obj.id
            })
          }
          _.cancelMySelect()
        } else {
          if (location.hash == '#admin') {
            menu.openTableMenu(e)
            return
          }
        }
      }
    }
    _.table.onmousemove = e => {
      if (!_.selected) {
        return
      }
      _.selected.pointer.style.left = e.pageX - _.selected.objX + 'px'
      _.selected.pointer.style.top = e.pageY - _.selected.objY + 'px'
    }
    _.table.style.width = width + 'px'
    _.table.style.height = height + 'px'
  },
  addObject(obj) {
    if (!_.table) {
      return
    }
    const objE = document.createElement('div')
    _.table.appendChild(objE)
    _.objects[obj.id] = objE
    objE.obj = obj
    objE.className = obj.turned ? 'object turned' : 'object'
    if (obj.backsrc) {
      const backE = document.createElement('img')
      objE.appendChild(backE)
      backE.className = 'back'
      backE.src = obj.backsrc
      backE.draggable = false
    }
    const frontE = document.createElement('img')
    objE.appendChild(frontE)
    frontE.className = 'front'
    frontE.src = obj.src
    frontE.draggable = false
    if (obj.rotate) {
      objE.style.transform = `rotateZ(${objE.obj.rotate}deg)`
    }
    objE.onmouseup = e => {
      if (_.selected || menu.isOpen() && e.button != 2) {
        return
      }
      e.stopPropagation()
      if (e.button == 2 && location.hash == '#admin') {
        menu.openObjectMenu(e, objE)
        return
      }
      if (objE.player != null) {
        return
      }
      if (e.button == 0) {
        _.select(objE, e.offsetX, e.offsetY)
      } else if (e.button == 2) {
        if (!obj.backsrc) {
          return
        }
        _.send({
          type: 'turn',
          objectId: obj.id
        })
      }
    }
    objE.style.width = obj.width + 'px'
    objE.style.height = obj.height + 'px'
    objE.style.left = obj.left + 'px'
    objE.style.top = obj.top + 'px'
  },
  select(objE, offsetX, offsetY) {
    if (_.selected || objE.player != null || objE.obj.fixed) {
      return
    }
    _.send({
      type: 'select',
      objectId: objE.obj.id
    })
    const pointer = document.createElement('div')
    _.table.appendChild(pointer)
    pointer.className = 'pointer'
    pointer.style.width = objE.style.width
    pointer.style.height = objE.style.height
    pointer.style.left = objE.style.left
    pointer.style.top = objE.style.top
    pointer.style.transform = objE.style.transform
    pointer.style.border = '2px dashed ' + _.players[_.me].color
    _.selected = {
      element: objE,
      objX: offsetX,
      objY: offsetY,
      pointer
    }
  },
  selectAll(objE, list, offsetX, offsetY) {
    if (_.selected) {
      return
    }
    for (const ee of list) {
      if (ee.player != null || ee.obj.fixed) {
        return
      }
    }
    list = list.map(ee => ee.obj.id)
    _.send({
      type: 'selectAll',
      list
    })
    const pointer = document.createElement('div')
    _.table.appendChild(pointer)
    pointer.className = 'pointer'
    pointer.style.width = objE.style.width
    pointer.style.height = objE.style.height
    pointer.style.left = objE.style.left
    pointer.style.top = objE.style.top
    pointer.style.transform = objE.style.transform
    pointer.style.border = '2px dashed ' + _.players[_.me].color
    _.selected = {
      element: objE,
      objX: offsetX,
      objY: offsetY,
      pointer,
      list
    }
  },
  cancelMySelect() {
    if (!_.selected) {
      return
    }
    _.table.removeChild(_.selected.pointer)
    _.selected = null
  },
  cancelMySelectIf(objectId) {
    if (!_.selected) {
      return
    }
    if (_.selected.element.obj.id == objectId) {
      _.cancelMySelect()
    } else if (_.selected.list) {
      for (const id of _.selected.list) {
        if (id == objectId) {
          _.cancelMySelect()
          break
        }
      }
    }
  },
  playerSelect(player, objectId) {
    const objE = _.objects[objectId]
    if (!objE) {
      return
    }
    if (player != _.me) {
      _.cancelMySelectIf(objectId)
    }
    _.table.appendChild(objE)
    objE.style.boxShadow = '0 0 10px 2px ' + _.players[player].color
    objE.player = player
  },
  playerCancelSelect(objectId) {
    const objE = _.objects[objectId]
    if (!objE) {
      return
    }
    objE.style.boxShadow = ''
    delete objE.player
  },
  playerMove(objectId, toX, toY) {
    const objE = _.objects[objectId]
    if (!objE) {
      return
    }
    objE.obj.left = toX
    objE.obj.top = toY
    objE.style.left = toX + 'px'
    objE.style.top = toY + 'px'
    objE.style.boxShadow = ''
    delete objE.player
  },
  playerMoveDelta(objectId, deltaX, deltaY) {
    const objE = _.objects[objectId]
    if (!objE) {
      return
    }
    objE.obj.left += deltaX
    objE.obj.top += deltaY
    objE.style.left = objE.obj.left + 'px'
    objE.style.top = objE.obj.top + 'px'
    objE.style.boxShadow = ''
    delete objE.player
  },
  playerCancelSelectPlayer(player) {
    for (const objE of _.table.children) {
      if (objE.player == player) {
        objE.style.boxShadow = ''
        delete objE.player
        break
      }
    }
  },
  turn(objectId) {
    const objE = _.objects[objectId]
    if (!objE) {
      return
    }
    objE.obj.turned = !objE.obj.turned
    objE.classList.toggle('turned')
  },
  rotate(objectId, deg) {
    const objE = _.objects[objectId]
    if (!objE) {
      return
    }
    if (objE.obj.rotate == null) {
      objE.obj.rotate = 0
    }
    objE.obj.rotate += deg
    objE.style.transform = `rotateZ(${objE.obj.rotate}deg)`
  },
  fixObject(objectId, fixed) {
    const objE = _.objects[objectId]
    if (!objE) {
      return
    }
    _.cancelMySelectIf(objectId)
    _.playerCancelSelect(objectId)
    objE.obj.fixed = fixed
  },
  putObjectAtTop(objectId) {
    const objE = _.objects[objectId]
    if (!objE) {
      return
    }
    _.table.appendChild(objE)
  },
  putObjectAtBottom(objectId) {
    const objE = _.objects[objectId]
    if (!objE) {
      return
    }
    if (_.table.children[0] && _.table.children[0] != objE) {
      _.table.insertBefore(objE, _.table.children[0])
    }
  },
  removeObject(objectId) {
    const objE = _.objects[objectId]
    if (!objE) {
      return
    }
    _.cancelMySelectIf(objectId)
    _.table.removeChild(objE)
    delete _.objects[objectId]
  }
}
